[Android] Kotlin AnkoでXMLを使わないレイアウト作成
AnkoはJetBrainsが開発しているKotlin向けのUI構築用のDSL *1ライブラリです。
通常Android開発で画面を作成するにはXMLで定義しますが、Ankoを入れることによりコード上でUIを簡潔に記述できます。例えば、EditTextとButtonのシンプルな構成の場合、XMLとコードとAnkoの記述差は下記図のようになります。
今回はそんなAnkoを導入するところから試してみました。ライセンスはApache License2.0です。
https://github.com/Kotlin/anko
検証環境
今回は下記環境で試しています。
Android Studio | 2.2.3 for MAC |
minSdkVersion | 19 |
targetSdkVersion | 25 |
Kotlin Version | 1.0.6 |
準備
プロジェクトの新規作成
AndroidStudioで新しくプロジェクトを作成します。
プロジェクト名と保存先を指定します。
今回はEmptyActivityにしました。
右下のFinishボタンを押して作成完了です。
Kotolinプラグインのインストール
既にKotolinを導入済みの方はこの手順は不要です。
Android Studio > Preferences... > Plugins > Browse repositories... をクリックします。
一覧からKotlinを選択しInstallボタンをクリックします。
インストールの完了後、AndroidStudioを再起動します。
Anko DSL Preview プラグインのインストール (要:環境の確認)
Ankoで作成した画面を表示するAnko DSL Previewというプラグインがあります。
こちらのプラグインですが、現時点(2017/1/5)では、新しいバージョンである、AndroidStudio 2.2.3をサポートしていません。
https://github.com/Kotlin/anko/issues/202
サポートされていない状態で、Anko DSL Previewをインストールすると'Cannot Load Project'というエラーが出ます。
その場合は、AndroidStudioを対応している古いバージョンに変更するか、Anko DSL Previewをアンインストールする(使うのをあきらめる)必要があります。アンインストールする場合は、 Android Studio > Preferences... > Plugins から Anko DSL Preview を選択し、Uninstallボタンをクリックしてください。今回の検証では使うのを諦めました。
Gradleの設定
作成したプロジェクトを開いた状態で、cmd + shift + aを押してFind Actionを開きます。
(Windowsの場合は Ctrl + Shift + A ?)
検索窓にKotlinと入力して、一覧に出てきた Configure Kotlin in Project をクリックします。
Android with Gradle を選びました。
対象は All modules、Kotlinのバージョンは現時点でのリリース版最新の1.0.6にしました。
次にbuild.gradleファイルにAnkoを追加します。必ず必要なのはAnko-SDKです。Anko-SDKはminSdkVersionによって選びます。
minSdkVersion | Anko-SDK |
---|---|
15〜18 | org.jetbrains.anko:anko-sdk15 |
19〜20 | org.jetbrains.anko:anko-sdk19 |
21〜22 | org.jetbrains.anko:anko-sdk21 |
23〜 | org.jetbrains.anko:anko-sdk23 |
また、必要に応じて以下のライブラリを追加します。
- org.jetbrains.anko:anko-support-v4
- org.jetbrains.anko:anko-appcompat-v7
- org.jetbrains.anko:anko-cardview-v7
- org.jetbrains.anko:anko-gridlayout-v7
- org.jetbrains.anko:anko-recyclerview-v7
- org.jetbrains.anko:anko-design
- org.jetbrains.anko:anko-percent
今回は 'com.android.support:appcompat-v7:' しか追加していないので、Ankoでは 'org.jetbrains.anko:anko-appcompat-v7:' しか追加していません。
dependencies { 〜 中略 〜 // Anko SDK compile 'org.jetbrains.anko:anko-sdk19:0.8.3' // Anko libs matching support libs compile 'org.jetbrains.anko:anko-appcompat-v7:0.8.3' }
※ 最新は0.9.1でしたが、エラーが出てしまったために0.8.3にしました。
Kotlinにコンバートする
MainActivityを選択し、 Code > Convert Java File to Kotlin File を選択します。
パスがjavaになっていたのでkotlinに変更しました。
コンバートが成功したかどうか確かめるために一度、シミュレーターで起動します。
エラーが出ずに起動されれば準備は完了です。
実装サンプル
MainActivityのonCreate()内の setContentView(R.layout.activity_main) を削除し、verticalLayout { … } 部分を追加しました。
package jp.classmethod.kotlinankosample import android.app.Activity import android.os.Bundle import org.jetbrains.anko.* class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) verticalLayout { textView("Hello world") button("Push") } } }
上記を実行すると下記のような表示になります。
また、UI部分をクラスにすることも出来ます。
AnkoComponent interfaceを実装したUIクラスを作成します。下記コードでは、class MainActivityUi: AnkoComponent
package jp.classmethod.kotlinankosample import android.app.Activity import android.os.Bundle import android.support.v4.content.ContextCompat import android.view.Gravity import android.text.InputType.TYPE_CLASS_TEXT import android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD import org.jetbrains.anko.* class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) MainActivityUi().setContentView(this) } fun tryLogin(ui: AnkoContext<MainActivity>, name: CharSequence?, password: CharSequence?) { ui.async() { Thread.sleep(500) activityUiThreadWithContext { if (checkInputText(name.toString(), password.toString())) { toast("ようこそ!") } else { toast("エラー:入力してください") } } } } private fun checkInputText(name: String, password: String) = name.length != 0 && password.length != 0is) } class MainActivityUi: AnkoComponent<MainActivity> { override fun createView(ui: AnkoContext<MainActivity>) = with(ui) { verticalLayout { padding = dip(32) imageView(android.R.drawable.ic_menu_edit).lparams { margin = dip(16) gravity = Gravity.CENTER } val name = editText { hint = "名前を入れて下さい" } val password = editText { hint = "パスワードを入れて下さい" inputType = TYPE_CLASS_TEXT or TYPE_TEXT_VARIATION_PASSWORD } button("Log in") { lparams(width = dip(160)) { topMargin = dip(32) gravity = Gravity.CENTER } textColor = ContextCompat.getColor(ctx, R.color.white) backgroundColor = ContextCompat.getColor(ctx, R.color.skyBlue) onClick { ui.owner.tryLogin(ui, name.text, password.text) } } } } }
さいごに
最初は見慣れなくて戸惑いましたが、見慣れてきたら直感的に書ける気がしてきました。まだ 今回はじめてKotlinをさわってみたため記載内容に気になる箇所がありましたら、ご指摘頂ければ幸いです。